home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / ddj0190.arc / TRACY.LST < prev    next >
File List  |  1989-12-19  |  42KB  |  1,269 lines

  1. SCREEN 0
  2. \ ZEN version 1.60-- a simple classical Forth      
  3.   ZEN 1.60 is a model implementation of the unofficial
  4.   ANS Forth with Double-Number, File Access, and BLOCK
  5.   Standard Extensions (BASIS6). This model is not endorsed 
  6.   by the ANS X3J14 committee. { Comments to go back to the ANS committee look 
  7.   like this.} ZEN 1.60 generates an IBM PC 64K small-model ROM-able nucleus.
  8.   BX register is top-of-stack.  DTC with JMP code field.
  9.   Assumes segment registers  CS = DS = ES Thanks to Wil Baden for his 
  10.   suggestions. This is a working document.  No guarantees are made to its
  11.   accuracy or fitness.  While this is a working document, it is
  12.   copyrighted 1989 by Martin J. Tracy.  All rights are reserved.
  13.  
  14. SCREEN 1
  15. \ ZEN nucleus
  16. FORTH DEFINITIONS  8 K-OF-ROM !  " KERNEL.COM" MAKE-OBJECT
  17.  
  18. 32  CONSTANT #Jot    ( number conversion area in bytes)
  19. 128 CONSTANT #Safe   ( CREATE safety area--   in bytes)
  20. 128 CONSTANT #User   ( total user area size-- in bytes)
  21.  
  22. HEX
  23. 0100 BFFF 2DUP 2CONSTANT #ROM  ROMORG 2!  ( start & end of ROM)
  24. C000 FFFF 2DUP 2CONSTANT #RAM  RAMORG 2!  ( start & end of RAM)
  25. 0000 #User - CONSTANT #RP0  ( top of return stack)
  26. #RP0  0080 - CONSTANT #SP0  ( top of data   stack)
  27.  
  28. START   DECIMAL 2 LOAD   FINIS
  29.  
  30. SCREEN 2
  31. \ Main LOAD screen
  32. HERE EQU Power  2 CELLS ( power-up) GAP   ," C 1989 by M Tracy"
  33. HERE EQU D0   #ROM , ,  #RAM , ,
  34. HERE EQU H0 ( h) 0 ,    HERE EQU F0  0 , 0 ,  ( forth vlink)
  35. HERE EQU T0 ( r) 0 ,    HERE EQU S0   #SP0 ,
  36.  
  37.            7 17 THRU  ( Kernel primitives)
  38.           19 27 THRU  ( Numbers and I/O)
  39.           29 41 THRU  ( Interpreter)
  40.           43 69 THRU  ( Compiler)
  41.           71 75 THRU  ( Device dependencies)
  42.           81 86 THRU  ( Mass storage extension)
  43.           77 79 THRU  ( Initialization)
  44.                       ( Application, if any)
  45.  
  46. HERE H0 !   THERE T0 !
  47.  
  48. SCREEN 3
  49. \ Documentation requirements
  50. ZEN 1.60 supports Double-Number, File Access, and BLOCK Standard Extensions.
  51. To compile the BLOCK extension, load the two screens following the File Access 
  52. extension. There are two 8-bit bytes per cell. Counted strings may be as long 
  53. as 255 bytes. Division is rounded-down. To change to floored division, load the
  54. two screens following the mixed-precision rounded-down operators. The system 
  55. dictionary is approximately 7K address units (au's) leaving 56K for the 
  56. application. {#RAM and #ROM are currently set for 40K of application dictionary
  57. and 16K of RAM.} {The data stack grows downwards towards the bottom of RAM.}
  58. {The return stack is currently set for 128 au's of RAM.} Only dumb (glass) 
  59. terminals are supported. { How are minimum facilities to be specified?}
  60.  
  61. SCREEN 4
  62. \ Errors and exceptions
  63. If the input stream is inadvertantly exhausted: ABORT" ?"
  64. If a word is not found: ABORT" ?"
  65. If control structures are incorrectly nested: ABORT" Unbalanced"
  66. If insufficient space in the dictionary: ABORT" No Room"
  67. If insufficient number of stack entries: ABORT" Stack?"
  68. If FORGETing within the nucleus: ABORT" Can't"
  69.  
  70. Division by zero returns a quotient of zero and a remainder
  71. equal to the dividend.
  72. Data and return stack overflows are not detected: the system
  73. may crash or hang, if you are lucky.
  74. Execution of compiler words while interpreting is not prevented;
  75. the result of such execution is undefined.
  76. Invalid and out-of-range arguments are not checked: the result
  77. of using such arguments is very undefined.
  78.  
  79. SCREEN 5
  80. \ Key to auxiliary commands
  81. Several words used by the metacompiler are described here.
  82.  
  83. |              make the next word headerless.
  84. ," ccc"        compile the characters "ccc."
  85.  
  86. a ORG          reset HERE to address a.
  87. n EQU <name>   equivalent to a headerless constant with value n.
  88. LABEL <name>   equivalent to  HERE EQU <name> but also activates
  89.                the CODE assembler.
  90. CODE <name>    begins a machine-code definition, usually ended
  91.                by  END-CODE  or  C;
  92.  
  93. I> and >I      like R> and >R when used to get return addresses.
  94.  
  95. BASE is returned to DECIMAL after each block is LOADed.
  96.  
  97. SCREEN 6
  98.  --------------------------------------------------------------
  99. |                                                              |
  100. |  Please direct all comments and inquiries to Martin Tracy    |
  101. |                                                              |
  102. |                                                              |
  103.  --------------------------------------------------------------
  104.  
  105. SCREEN 7
  106. \ ------ Kernel primitives ------------------------
  107. LABEL colon   BP DEC  BP DEC   SI 0 [BP] MOV   SI POP   NEXT
  108. \ save I register on return stack and set it to new position.
  109. \ This is the action of the code field in all colon definitions.
  110.  
  111. CODE EXIT   NOP
  112. | CODE semi   0 [BP] SI MOV   BP INC  BP INC
  113. | CODE nope   NEXT C;
  114. \ semi is the action of the semicolon in all colon definitions.
  115. \ EXIT differs from semi as an aid to decompilation.
  116. \ nope is a "no operation" word used for initialization.
  117.  
  118.  
  119. SCREEN 8
  120. \ Data objects
  121. LABEL addr  \ the action of all CREATEs.
  122.    BX PUSH   3 # AX ADD  BX AX XCHG   NEXT
  123.  
  124. LABEL con   \ the action of all CONSTANTs and VARIABLEs.
  125.    BX PUSH   3 # AX ADD  BX AX XCHG   0 [BX] BX MOV   NEXT C;
  126.  
  127. VARIABLE u  { Private}  \ USER area pointer.
  128. LABEL uvar  \ the action of all USER variables.
  129.    BX PUSH   3 # AX ADD   BX AX XCHG
  130.    0 [BX] BX MOV   u ) BX ADD   NEXT
  131.  
  132. LABEL (does)   BP DEC  BP DEC  SI 0 [BP] MOV  \ run-time DOES>
  133.    SI POP  BX PUSH   3 # AX ADD   BX AX XCHG    NEXT C;
  134.  
  135. SCREEN 9
  136. \ Stack manipulation
  137. CODE DUP  ( w - w w)   BX PUSH   NEXT C;
  138. CODE DROP ( w)         BX POP    NEXT C;
  139.  
  140. CODE SWAP ( w w2 - w2 w)
  141.    SP DI MOV             BX 0 [DI] XCHG   NEXT C;
  142. CODE OVER ( w w2 - w w2 w)
  143.    SP DI MOV   BX PUSH   0 [DI] BX MOV    NEXT C;
  144.  
  145. CODE ROT ( w w2 w3 - w2 w3 w)
  146.    DX POP  AX POP   DX PUSH  BX PUSH   AX BX MOV   NEXT C;
  147.  
  148. CODE PICK ( w[u]...w[1] w[0] u - w[u]...w[1] w[0] w[u])
  149. \ copy kth item to top of stack.
  150.    BX SHL   SP BX ADD   0 [BX] BX MOV   NEXT C;
  151.  
  152. SCREEN 10
  153. \ Memory access
  154. CODE @ ( a - w)   0 [BX] BX MOV        NEXT C;
  155. CODE ! ( w a)     0 [BX] POP  BX POP   NEXT C;
  156.  
  157. CODE C@ ( a - b)  0 [BX] BL MOV   BH BH SUB        NEXT C;
  158. CODE C! ( b a)    AX POP  AL 0 [BX] MOV   BX POP   NEXT C;
  159.  
  160. CODE CMOVE ( a a2 u)
  161. \ move count bytes from from to to, leftmost byte first.
  162.    BX CX MOV   SI BX MOV   DI POP  SI POP
  163.    REP BYTE MOVS   BX SI MOV   BX POP   NEXT C;
  164.  
  165. SCREEN 11
  166. \ Math operators
  167. | CODE tic   NOP
  168. | CODE lit   WORD LODS   BX PUSH  AX BX MOV    NEXT C;
  169. \ push the following (in-line) number onto the stack.
  170.  
  171. CODE + ( n n2 - n3)   AX POP  AX BX ADD            NEXT C;
  172. CODE - ( n n2 - n3)   AX POP  AX BX SUB   BX NEG   NEXT C;
  173.  
  174. CODE NEGATE ( n -  n2)   BX NEG   NEXT C;
  175. CODE ABS    ( n - +n2)
  176.    BX BX OR  1 L# JNS   BX NEG   1 L: NEXT C;
  177.  
  178. CODE +! ( n a)   AX POP   AX 0 [BX] ADD  BX POP   NEXT C;
  179. \ increment number at address by n.
  180.  
  181. SCREEN 12
  182. \ Math and logical
  183. CODE 1+ ( n - n2)   BX INC   NEXT C;
  184. CODE 1- ( n - n2)   BX DEC   NEXT C;
  185.  
  186. CODE 2* ( n - n2)   BX SHL   NEXT C;  { CONTROLLED} { Require?}
  187. CODE 2/ ( n - n2)   BX SAR   NEXT C;  ( arithmetic)
  188.  
  189. CODE AND ( m m2 - m3)   AX POP  AX BX AND    NEXT C;
  190. CODE OR  ( m m2 - m3)   AX POP  AX BX OR     NEXT C;
  191. CODE XOR ( m m2 - m3)   AX POP  AX BX XOR    NEXT C;
  192.  
  193. CODE NOT ( w - w2)   BX NOT   NEXT C;  { ( m - m2) ?}
  194.  
  195. SCREEN 13
  196. \ Comparisons
  197. CODE 0 ( - n)      BX PUSH   BX BX SUB    NEXT C;  { Feature}
  198. CODE 1 ( - n)      BX PUSH   1 # BX MOV   NEXT C;  { Feature}
  199. CODE TRUE ( - m)   BX PUSH  -1 # BX MOV   NEXT C;  { Control?}
  200.  
  201. CODE = ( n n2 - f)   AX POP  AX BX CMP
  202.    TRUE # BX MOV  1 L# JZ   BX INC   1 L: NEXT C;
  203.  
  204. CODE <  ( n n2 - f)   AX POP  BX AX SUB
  205.    TRUE # BX MOV  1 L# JL   BX INC   1 L: NEXT C;
  206. CODE U< ( u u2 - f)   AX POP  BX AX SUB
  207.    TRUE # BX MOV  1 L# JB   BX INC   1 L: NEXT C;
  208.  
  209. : > ( n n2 - f)   SWAP < ;
  210.  
  211. SCREEN 14
  212. \ Comparisons against zero and CELL operators
  213. CODE 0= ( n - f)
  214.    BX BX OR  TRUE # BX MOV  1 L# JZ   BX INC   1 L: NEXT C;
  215. CODE 0< ( n - f)
  216.    BX BX OR  TRUE # BX MOV  1 L# JS   BX INC   1 L: NEXT C;
  217.  
  218. : 0> ( n - f)   0 > ;
  219.  
  220.  
  221. 2 CONSTANT CELL  { Feature}
  222.  
  223. CODE CELL+ ( a - a2)   BX INC  BX INC   NEXT C;
  224. CODE CELLS ( a - a2)   BX SHL           NEXT C;
  225.  
  226. SCREEN 15
  227. \ Branches and loops
  228. | CODE  branch         \ unconditional branch.
  229.    0 [SI] SI MOV   NEXT C;
  230. | CODE ?branch ( f)    \ branch if zero.
  231.    BX BX OR  BX POP    ' branch JZ   2 # SI ADD   NEXT C;
  232.  
  233. | CODE (do) ( n n2)    \ begin DO...LOOP structure.
  234.    4 # BP SUB      AX POP   HEX 8000 DECIMAL # AX ADD
  235.    AX 2 [BP] MOV   AX BX SUB   BX 0 [BP] MOV   BX POP   NEXT C;
  236.  
  237. | CODE (loop)         \ terminate DO...LOOP structure.
  238.    WORD 0 [BP] INC  ' branch JNO
  239. LABEL  >loop   2 # SI ADD
  240. | CODE >undo   4 # BP ADD   NEXT
  241. | CODE (+loop) ( n)   \ terminate DO...+LOOP structure.
  242.    BX 0 [BP] ADD  BX POP  ' branch JNO  >loop JO   NEXT C;
  243.  
  244. SCREEN 16
  245. \ Return stack
  246. CODE >R ( w)    BP DEC  BP DEC  BX 0 [BP] MOV   BX POP  NEXT C;
  247.  
  248. CODE R@ ( - w)  BX PUSH  0 [BP] BX MOV   NEXT C;
  249. CODE I  ( - n)  BX PUSH  0 [BP] BX MOV  2 [BP] BX ADD   NEXT C;
  250. CODE J  ( - n)  BX PUSH  4 [BP] BX MOV  6 [BP] BX ADD   NEXT C;
  251. CODE R> ( - w)  BX PUSH  0 [BP] BX MOV  BP INC  BP INC  NEXT C;
  252.  
  253. CODE 2>R ( w w2)
  254. \ push w and w2 to the return stack, w2 on top.
  255.    4 # BP SUB   BX 0 [BP] MOV   2 [BP] POP   BX POP     NEXT C;
  256.  
  257. CODE 2R> ( - w w2)
  258. \ pop w and w2 from the return stack.
  259.    BX PUSH   2 [BP] PUSH   0 [BP] BX MOV   4 # BP ADD   NEXT C;
  260.  
  261. SCREEN 17
  262. \ Optimizations and EXECUTE
  263. CODE NIP  ( w w2 - w2)       { CONTROLLED}  AX POP   NEXT C;
  264. CODE TUCK ( w w2 - w2 w w2)  { CONTROLLED}  AX POP
  265.    BX PUSH  AX PUSH   NEXT C;
  266.  
  267. CODE ?DUP ( w - w w | 0 - 0)
  268.    BX BX OR  1 L# JZ   BX PUSH  1 L: NEXT C;
  269.  
  270. CODE EXECUTE ( w)   BX AX XCHG   BX POP   AX JMP C;
  271.  
  272. CODE @EXECUTE ( w)  { Control?}  { Why w and not a?}
  273. \ @EXECUTE is equivalent to @ EXECUTE but is much faster.
  274.    BX DI MOV   BX POP   0 [DI] AX MOV   AX JMP C;
  275.  
  276. SCREEN 18
  277.  
  278.  
  279.  
  280. SCREEN 19
  281. \ ------ Input/Output -----------------------------
  282. \ In ZEN, consecutive headerless variables form a category
  283. \ which can be extended but not reduced or reordered.
  284.  
  285. 0 USER entry  2 CELLS + ( skip multitasking hooks)
  286.   USER r      | USER SP0
  287.   USER x      \ XFER vector pointer.
  288.   USER BASE   | USER dpl    | USER hld   EQU #I/0
  289.  
  290. : THERE ( - a)   r @ ;  { ROM}
  291. : PAD   ( - a)   r @ [ #Jot ] LITERAL + ;  { CONTROLLED}
  292. { pictured number staging area size undefined?}
  293.  
  294. : DECIMAL   10 BASE ! ;
  295. : HEX       16 BASE ! ;  { CONTROLLED}
  296.  
  297. SCREEN 20
  298. \ Double-value data stack operators
  299. CODE 2DUP ( w w2 - w w2 w w2)   SP DI MOV   BX PUSH
  300.    0 [DI] PUSH   NEXT C;
  301.  
  302. CODE 2DROP ( w w2)   BX POP  BX POP   NEXT C;
  303.  
  304. CODE 2SWAP ( w w2 w3 w4 - w3 w4 w w2)   AX POP  CX POP  DX POP
  305.    AX PUSH  BX PUSH  DX PUSH  CX BX MOV   NEXT C;
  306.  
  307. : 2OVER ( d d2 - d d2 d)       2>R 2DUP  2R> 2SWAP ;
  308. : 2ROT  ( d d2 d3 - d2 d3 d)   2R> 2SWAP 2R> 2SWAP ;
  309. { CONTROLLED}  { Require?}
  310.  
  311. CODE 2@ ( a - w w2)   2 [BX] PUSH  0 [BX] BX MOV        NEXT C;
  312. CODE 2! ( w w2 a)     0 [BX] POP   2 [BX] POP   BX POP  NEXT C;
  313.  
  314. SCREEN 21
  315. \ Numeric conversion math support
  316. CODE D+ ( d d2 - d3)   AX POP   DX POP   CX POP
  317.    AX CX ADD   CX PUSH    DX BX ADC   NEXT C;
  318.  
  319. CODE DNEGATE ( d - d2)   AX POP  AX NEG  AX PUSH
  320.    0 # BX ADC   BX NEG   NEXT C;
  321.  
  322. : MAX ( n n2 - n3)   2DUP <    IF  SWAP  THEN  DROP ;
  323. : MIN ( n n2 - n3)   2DUP < 0= IF  SWAP  THEN  DROP ;
  324.  
  325.  
  326. SCREEN 22
  327. \ Numeric conversion math support
  328. CODE UM* ( u u2 - ud)
  329.    AX POP   BX MUL    AX PUSH   DX BX MOV   NEXT C;
  330.  
  331. CODE UM/MOD ( ud u - u2 u3)
  332. \ return rem u2 and quot u3 of unsigned ud divided by u.
  333. \ On zero-divide, return quot=0 and rem=low-word-of-ud.
  334.    DX POP  AX AX SUB  BX DX CMP  1 L# JAE
  335.    AX POP  BX DIV  DX PUSH       1 L: AX BX MOV   NEXT C;
  336.  
  337.  
  338. SCREEN 23
  339. \ Input number conversion
  340. ASCII A  ASCII 9  1+ - EQU A-10
  341.  
  342. | : digit ( c base - n t | ? 0)
  343. \ true if the char c is a valid digit in the given base.
  344.    SWAP [ASCII] 0 -  9 OVER <  DUP
  345.    IF  DROP  A-10 -  10  THEN
  346.    >R  DUP R@ -  ROT R> -  U< ;
  347.  
  348. : CONVERT ( +d a - +d2 a2)
  349. \ convert the char sequence at a+1 and accumulate it in +d.
  350. \ a2 is the address of the first non-convertable digit.
  351.    BEGIN  1+ DUP >R  C@ BASE @ digit
  352.    WHILE  SWAP  BASE @ UM* DROP  ROT  BASE @ UM*  D+  R>
  353.    REPEAT DROP  R> ;
  354.  
  355. SCREEN 24
  356. \ Output number conversion
  357. : <#   PAD hld ! ;
  358. : #> ( wd - a u)   2DROP hld @ PAD OVER - ;
  359.  
  360. : HOLD ( c)   TRUE hld +!  hld @ C! ;
  361. \ add character c to output string.
  362. : SIGN ( n)   0< IF  [ASCII] - HOLD  THEN ;
  363. \ add "-" to output string if w is negative.
  364.  
  365. : # ( ud - ud2)
  366. \ transfer the next digit of ud to the output string.
  367.    BASE @ >R  0 R@ UM/MOD  R> SWAP >R  UM/MOD  R>
  368.    ROT 9 OVER < IF  A-10 + THEN  [ASCII] 0 + HOLD ;
  369.  
  370. : #S ( ud - ud2)   BEGIN  #  2DUP OR  0= UNTIL ;
  371. \ convert all remaining digits of ud.  ud2 is 0 0 .
  372.  
  373. SCREEN 25
  374. \ Transfers
  375. LABEL xvar  \ the action of all transfers.
  376.    u ) DI MOV   x [DI] DI MOV   3 # AX ADD   DI AX XCHG
  377.    0 [DI] DI MOV   AX DI ADD   0 [DI] AX MOV   AX JMP C;
  378.  
  379. 0 XFER TYPE ( a u)              XFER CR
  380.   XFER KEYS ( a u) { Private}   XFER KEY? ( - f) { Extend?}
  381.   XFER MARK ( a u) { Extend?}   XFER PAGE        { Extend?}
  382.   XFER TAB ( n n2) { Extend?} ( Reserved)  DROP
  383.  
  384. \ KEYS is a simple unfiltered EXPECT which doesn't echo.
  385. \ KEY? is true if a key is available.
  386. \ MARK is like TYPE but highlights if possible.
  387. \ PAGE clears the screen.
  388. \ TAB  moves the cursor to the x (n) and y (n2) coordinates.
  389.  
  390. SCREEN 26
  391. \ Print spaces
  392. 32 CONSTANT BL  { CONTROLLED}   \ ASCII blank
  393.  
  394.      HERE ( *) BL ,
  395. : SPACE   ( *) LITERAL 1 TYPE ;
  396.  
  397. HERE ( * )  BL C, BL C, BL C, BL C, BL C, BL C, BL C, BL C,
  398. : SPACES ( +n )  \ output w spaces.   Optimized for TYPE.
  399.    ( * ) LITERAL  OVER 2/ 2/ 2/  ?DUP
  400.    IF  0 DO  DUP 8 TYPE  LOOP  THEN  SWAP 7 AND TYPE ;
  401.  
  402. SCREEN 27
  403. \ Print numbers
  404. | : (d.) ( d - a u)   \ convert a double number to a string.
  405.    TUCK  DUP 0< IF  DNEGATE  THEN  <#  #S ROT SIGN  #> ;
  406.  
  407. : D. ( d)   (d.) TYPE SPACE ;
  408. : U. ( u)        0 D. ;
  409. :  . ( n)   DUP 0< D. ;
  410.  
  411. SCREEN 28
  412.  
  413. SCREEN 29
  414. \ ------ Interpreter ------------------------------
  415. #I/O ( continued from I/O layer)
  416.   USER BLK  { BLOCK} { Require?}   USER >IN   \ keep together.
  417.   USER #TIB   CELL+   \ #TIB and TIB's value.
  418.   USER SPAN
  419.   USER STATE  EQU #Used
  420.  
  421.   VARIABLE last   CELL ALLOT     \ last lfa and cfa.
  422. | VARIABLE scr    CELL ALLOT     \ last error location.
  423. | VARIABLE bal  | VARIABLE leaf  \ see compiler.
  424.  
  425. VARIABLE CONTEXT  { CONTROLLED}
  426. VARIABLE CURRENT  { CONTROLLED}
  427.  
  428. : TIB ( - a)   #TIB CELL+ @ ;
  429.  
  430. SCREEN 30
  431. \ Automatic variables
  432. \ These variables are automatically initialized; see COLD.
  433. VARIABLE h   | VARIABLE f   CELL ( ie vlink) ALLOT
  434.  
  435.   VARIABLE 'pause    \ multitasking hook.
  436. | VARIABLE 'expect   \ deferred EXPECT
  437. | VARIABLE 'source   \ deferred input stream.
  438. | VARIABLE 'warn     \ redefinition warning.
  439. | VARIABLE 'loc      \ source location field.
  440. | VARIABLE 'val?     \ string to number conversion.
  441.  
  442. | VARIABLE key'  CELL ALLOT   \ one-key look-ahead buffer.
  443.  
  444. : HERE ( - a)   h @ ;
  445.  
  446. SCREEN 31
  447. ( String operators-- high-level definitions )  EXIT
  448. : COUNT ( a - a2 u)   DUP C@ SWAP 1+ ;
  449. \ transform counted string into text string.
  450. : /STRING ( a u n - a2 u2)  { Control?}  ROT OVER + ROT ROT - ;
  451. \ truncate leftmost n chars of string.  n may be negative.
  452.  
  453. : SKIP ( a u b - a2 u2)  { Control?}
  454. \ return shorter string from first position unequal to byte.
  455.    >R  BEGIN  DUP
  456.        WHILE  OVER C@ R@ - IF  R> DROP  EXIT  THEN  1 /STRING
  457.        REPEAT   R> DROP ;
  458. : SCAN ( a u b - a2 u2)  { Control?}
  459. \ return shorter string from first position equal to byte.
  460.    >R  BEGIN  DUP
  461.        WHILE  OVER C@ R@ =  IF  R> DROP  EXIT  THEN  1 /STRING
  462.        REPEAT   R> DROP ;
  463.  
  464. SCREEN 32
  465. ( String operators-- low-level definitions )
  466. CODE COUNT ( a - a2 u)   BX AX MOV   AX INC
  467. \ transform counted string into text string.
  468.    0 [BX] BL MOV   BH BH SUB   AX PUSH   NEXT C;
  469. CODE /STRING ( a u n - a2 u2)  { Control?}  CX POP  AX POP
  470. \ truncate leftmost n chars of string.  n may be negative.
  471.    BX AX ADD  BX CX SUB   CX BX MOV   AX PUSH   NEXT C;
  472.  
  473. CODE SKIP ( a u b - a2 u2) { Contr?}  BX AX MOV  CX POP  DI POP
  474. \ return shorter string from first position unequal to byte.
  475.    1 L# JCXZ   REPE BYTE SCAS    1 L# JZ    CX INC  DI DEC
  476.    1 L: DI PUSH  CX BX MOV   NEXT C;
  477. CODE SCAN ( a l b - a2 u2) { Contr?}  BX AX MOV  CX POP  DI POP
  478. \ return shorter string from first position equal to byte.
  479.    1 L# JCXZ   REPNE BYTE SCAS   1 L# JNZ   CX INC  DI DEC
  480.    1 L: DI PUSH  CX BX MOV   NEXT C;
  481.  
  482. SCREEN 33
  483. \ More string operators
  484. CODE FILL ( a u b)   \ store u b's, starting at addr a.
  485.    BX AX MOV  CX POP  DI POP   REP BYTE STOS   BX POP   NEXT C;
  486.  
  487. : -TRAILING ( a +n - a2 +n2)   2DUP
  488. \ alter string to suppress trailing blanks.
  489.    BEGIN  2DUP         BL SKIP  DUP
  490.    WHILE  2SWAP 2DROP  BL SCAN  REPEAT  2DROP  NIP - ;
  491.  
  492. EXIT
  493. : FILL ( a u b)   \ store u b's, starting at addr a.
  494.    SWAP ?DUP 0= IF  2DROP EXIT  THEN
  495.    >R OVER C!  DUP 1+ R> 1- CMOVE ;
  496.  
  497. SCREEN 34
  498. \ Input stream operators
  499. | : source ( - a u)   #TIB 2@ ;   \ input stream source.
  500. :  /source ( - a u)   'source @EXECUTE  >IN @ /STRING ;
  501.  
  502. | : accept ( n f)   IF  1+  THEN  >IN +! ;
  503. \ accept characters by incrementing >IN.
  504.  
  505. : parse ( c - a u)   \ parse a character-delimited string.
  506.    >R  /source  OVER SWAP  R> SCAN  >R  OVER -  DUP R> accept ;
  507.  
  508. : WORD ( c - a)      \ parse a character-delimited string;
  509. \ leading delimiters are accepted and skipped;
  510. \ the string is counted and followed by a blank (not counted).
  511.    >R  /source  OVER R> 2>R  R@ SKIP  OVER SWAP  R> SCAN
  512.    OVER R> -  SWAP accept  OVER -  31 MIN  THERE  DUP >R
  513.    2DUP C!  1+ SWAP CMOVE  BL R@ COUNT + C!  R> ;
  514.  
  515. SCREEN 35
  516. \ Dictionary search
  517. CODE thread ( a w - a 0 , cfa -1 , cfa 1)
  518. \ search vocabulary for a match with the packed name at  a .
  519.    DX POP  SI PUSH
  520.  1 L: 0 [BX] BX MOV                ( chain thru dictionary )
  521.    BX BX OR  5 L# JZ               ( jump if end of thread )
  522.    DX DI MOV  ( 'string)   BX SI MOV  2 # SI ADD   ( SI=nfa)
  523.    0 [SI] CL MOV     31 # CX AND   0 [DI] CL CMP   ( count = ?)
  524.    1 L# JNZ ( lengths <>) DI INC  SI INC  ( to body of 'string)
  525.    REPE BYTE CMPS ( names =?)  1 L# JNZ   ( jump not matched)
  526.    CX POP   SI PUSH  ( cfa )
  527.    CX SI MOV   BYTE 32 # 2 [BX] TEST  ( immediate bit )
  528.    TRUE # BX MOV  4 L# JZ   BX NEG     4 L: NEXT
  529.  5 L: SI POP   DX PUSH ( 'str)  ( BX = 0)   NEXT C;
  530.  
  531. SCREEN 36
  532. \ FIND  [ and ]
  533. : FIND ( a - a 0 | a - w -1 | a - w 1)
  534. \ search dictionary for a match with the packed name at  a .
  535. \ Return execution address and -1 or 1 ( IMMEDIATE) if found;
  536. \ ['] EXIT 1 if  a  has zero length;  a 0  if not found.
  537.    DUP C@ ( a l) DUP
  538.    IF  31 MIN OVER C! ( a) CONTEXT @ thread ( a -1/0/1) DUP
  539.       IF  EXIT  THEN       CONTEXT @ f -
  540.       IF  DROP  f thread  THEN   EXIT
  541.    THEN ( a 0) 2DROP  ['] EXIT 1 ;
  542.  
  543. : ]  TRUE STATE ! ;  \ stop interpreting; start compiling.
  544. : [     0 STATE ! ;  \ stop compiling; start interpreting.
  545.   IMMEDIATE
  546.  
  547. SCREEN 37
  548. \ Data and return stack
  549. \ Set data and return stack pointers, respectively:
  550. | CODE sp! ( a)   BX SP MOV  BX POP   NEXT C;
  551. | CODE rp! ( a)   BX BP MOV  BX POP   NEXT C;
  552.  
  553. : RESET  { Feature}  \ reset return stack for error recovery.
  554.    I>  entry CELL - rp!  >I ;
  555. : PRESET { Feature}  \ empty both stacks and prepare system.
  556.    SP0 @ sp!  I> entry rp! >I  SP0 @ 0 #TIB 2!  0 STATE ! ;
  557.  
  558. | : err   RESET ;
  559.  
  560. CODE DEPTH ( - n)   \ # items on stack before DEPTH is executed.
  561.    BX PUSH   u ) BX MOV   SP0 [BX] BX MOV   SP BX SUB   BX SAR
  562.    NEXT C;
  563.  
  564. SCREEN 38
  565. ( Memory management-- high-level definitions)  EXIT
  566. : ALLOT ( n)   r +! ;   \ allocate n RAM data bytes.
  567. : GAP   ( n)   h +! ;   \ allocate n dictionary bytes.  { ROM}
  568.  
  569. : C, ( w)   h @ C!  1 h +! ;     \ ie  HERE C!  1 GAP ;
  570. \ append low byte of w onto the dictionary.
  571. : ,  ( w)   h @ !  CELL h +! ;   \ ie  HERE !  CELL GAP ;
  572. \ append w onto the dictionary.
  573.  
  574. EXIT  { In an all-RAM system:}
  575. : GAP   ALLOT ;   : THERE   HERE ;    : >DATA   >BODY ;
  576. : GOES>  [COMPILE] DOES> ;  IMMEDIATE
  577.  
  578. SCREEN 39
  579. ( Memory management-- low-level definitions)
  580. CODE ALLOT ( n)   \ allocate n RAM data bytes.
  581.    r # DI MOV   u ) DI ADD   BX 0 [DI] ADD  BX POP   NEXT C;
  582. CODE GAP   ( n)   \ allocate n dictionary bytes.  { ROM}
  583.    h # DI MOV                BX 0 [DI] ADD  BX POP   NEXT C;
  584.  
  585. CODE C, ( w)   h # DI MOV   0 [DI] DI MOV
  586. \ append low byte of w onto the dictionary.
  587.    BL 0 [DI] MOV   1 # BX MOV  ' GAP JU
  588. CODE ,  ( w)   h # DI MOV   0 [DI] DI MOV
  589. \ append w onto the dictionary.
  590.    BX 0 [DI] MOV   2 # BX MOV  ' GAP JU  FORTH
  591.  
  592. SCREEN 40
  593. \ Code and data fields
  594. : >BODY ( w - a)   3 + ;
  595. : >DATA ( w - a)   3 + @ ;  { ROM}
  596.  
  597. : >code ( cfa - 'code)  1+  DUP @ CELL+ + ;
  598. \ finds code address associated with cfa.
  599. | : alter ( 'code cfa)   1+  TUCK CELL+ -  SWAP ! ;
  600. \ point the cf to the given code addr.  Skip the CALL byte.
  601.  
  602. | : nest, ( 'code )   HERE  232 ( CALL) C,  CELL GAP  alter ;
  603. \ create the code field for colon words, DOES> and GOES>
  604. | : code, ( 'code )   HERE  233 ( JMP ) C,  CELL GAP  alter ;
  605. \ create the code field for data words.
  606.  
  607. : patch ( 'code cfa)   233 ( JMP ) OVER C!  alter ;
  608. \ make 'code the new action of the cf.  Used by (;code).
  609.  
  610. SCREEN 41
  611. \ Alignment, string and error primitives
  612. \ : ALIGN   HERE 1 AND GAP ;           { ALIGN}
  613. \ force dictionary to the next even address.
  614. \ : REALIGN ( a - a2)   DUP 1 AND + ;  { ALIGN}
  615. \ force address to the next even address.
  616.  
  617. | : (") ( - a l)   I> COUNT  2DUP +  ( REALIGN) >I ;
  618. \ leave the address and length of an in-line string.
  619.  
  620. | : huh? ( w)   0= ABORT" ?" ;
  621. \ error action of several words.
  622.  
  623. : ' ( - w)   BL WORD  DUP C@ huh?  FIND huh? ;
  624.  
  625. \ : I>   [COMPILE] R> ;  IMMEDIATE  { ALIGN}
  626. \ : >I   [COMPILE] >R ;  IMMEDIATE  { ALIGN}
  627.  
  628. SCREEN 42
  629.  
  630.  
  631. SCREEN 43
  632. \ ------ Compiler ---------------------------------
  633. : COMPILE   I>  DUP CELL+ >I  @ , ;
  634. \ compile the word that follows in the definition.
  635.  
  636. : header  \ create link and name fields.
  637.    ( ALIGN)              'loc  @EXECUTE  ( extra fields )
  638.    BL WORD  DUP C@ huh?  'warn @EXECUTE  ( redefinition?)
  639.    HERE last !  HERE CURRENT @ DUP @ , ! ( link field)
  640.    HERE OVER C@ 1+ CMOVE                 ( name field)
  641.    HERE C@ DUP 128 OR C, GAP   HERE last CELL+ ! ;
  642.  
  643. SCREEN 44
  644. \ Defining words
  645. : CREATE ( - a)
  646.    header  [ addr ] LITERAL code, ;
  647.  
  648. : VARIABLE ( - a)
  649.    header  [ con ] LITERAL code,  THERE ,
  650.    0 THERE ! ( courtesy )  CELL ALLOT ;
  651.  
  652. : CONSTANT ( - w)
  653.    header  [ con ] LITERAL code,  , ;
  654.  
  655. SCREEN 45
  656. \ DOES> and GOES>
  657. | : (;code)   I> last CELL+ @ patch ;
  658. \ the code field of (;code) is at  ' DOES> >BODY CELL+
  659.  
  660.  
  661. : DOES>   COMPILE (;code)  [ (does) ] LITERAL nest, ; IMMEDIATE
  662. \ eg  : KONST   CREATE  ,  DOES> @ ;
  663.  
  664. : GOES>  { ROM}  [COMPILE] DOES>  COMPILE @ ;  IMMEDIATE
  665. \ eg  : VALUE   VARIABLE   GOES> @ ;
  666.  
  667. SCREEN 46
  668. \ Literals
  669. : LITERAL ( - w)     COMPILE lit  , ;  IMMEDIATE
  670. \ compile w as a literal.
  671. : [']     ( - w)  '  COMPILE tic  , ;  IMMEDIATE
  672. \ compile-form of ' ("tick").
  673.  
  674. :  ASCII  ( - c)   BL WORD 1+ C@ ;  \ return value of next char.
  675. : [ASCII] ( - c)                   \ compile value of next char.
  676.    ASCII  [COMPILE] LITERAL ;  IMMEDIATE
  677.  
  678. : STRING ( c)  { Feature}  \ string compiler, eg 32 STRING ABC
  679.    parse  DUP C,  HERE OVER GAP  SWAP CMOVE  ( ALIGN) ;
  680.  
  681. : " ( - a u)    \ string literal, eg " cccc"
  682.    COMPILE (")  [ASCII] " STRING ;  IMMEDIATE
  683. : ."   [COMPILE] "  COMPILE TYPE ;  IMMEDIATE
  684.  
  685. SCREEN 47
  686. \ Flow of control
  687. | : ?bal   DUP bal @ < huh?  PICK @ 0= huh? ;
  688. | : -bal   bal @ huh?  TRUE bal +!  DUP @ huh? ;
  689.  
  690. : BEGIN  HERE  1 bal +! ;                          IMMEDIATE
  691.  
  692. : IF     COMPILE ?branch  [COMPILE] BEGIN   0 , ;  IMMEDIATE
  693. : THEN   0 ?bal  TRUE bal +!  HERE SWAP ! ;        IMMEDIATE
  694. : ELSE   0 ?bal  COMPILE  branch  [COMPILE] BEGIN  0 ,
  695.          SWAP   [COMPILE] THEN ;                   IMMEDIATE
  696.  
  697. : UNTIL  -bal  COMPILE ?branch  , ;                IMMEDIATE
  698. : AGAIN  -bal  COMPILE  branch  , ;  { Control?}   IMMEDIATE
  699. : WHILE   bal @ huh?  [COMPILE] IF  SWAP ;         IMMEDIATE
  700. : REPEAT  1 ?bal  [COMPILE] AGAIN [COMPILE] THEN ; IMMEDIATE
  701.  
  702. SCREEN 48
  703. \ Definite loops
  704. : DO   COMPILE (do)  [COMPILE] BEGIN ;   IMMEDIATE
  705.  
  706. : LEAVE  COMPILE >undo  COMPILE branch
  707.    HERE  leaf @ , leaf ! ;               IMMEDIATE
  708.  
  709. | : rake,   \ gathers leaf's.  Courtesy of Wil Baden.
  710.    DUP ,  leaf @
  711.    BEGIN  2DUP U< WHILE  DUP @ HERE ROT !  REPEAT
  712.    leaf ! DROP ;
  713.  
  714. :  LOOP  -bal  COMPILE  (loop)  rake, ;  IMMEDIATE
  715. : +LOOP  -bal  COMPILE (+loop)  rake, ;  IMMEDIATE
  716.  
  717. : UNDO   COMPILE >undo ;  IMMEDIATE
  718.  
  719. SCREEN 49
  720. \ Colon definitions
  721. : :   \ create a word and enter the compiling loop.
  722.    CURRENT @ CONTEXT !
  723.    header  [ colon ] LITERAL nest,
  724.    last @ @ CONTEXT @ !  0 0 bal 2!  ] ;
  725.  
  726. : ;   \ terminate a definition.
  727.    bal 2@ OR ABORT" Unbalanced"
  728.    last @ CURRENT @ !
  729.    COMPILE semi [COMPILE] [ ;  IMMEDIATE
  730.  
  731. SCREEN 50
  732. \ Vocabularies
  733. : FORTH   f CONTEXT ! ;
  734.  
  735. : DEFINITIONS   CONTEXT @ CURRENT ! ;
  736. \ new definitions will be into the CURRENT vocabulary.
  737.  
  738. : VOCABULARY
  739. \ when executed, a vocabulary becomes first in the search order.
  740.    VARIABLE   HERE  f CELL+ ( ie vlink) DUP @ , !
  741.    CELL GAP ( value for automatic initialization)
  742.    GOES> CONTEXT ! ;
  743.  
  744. SCREEN 51
  745. \ Misc. compiler support
  746. : IMMEDIATE   last @ CELL+  DUP C@ BL ( ie 32) OR SWAP C! ;
  747.  
  748. : [COMPILE]    ' , ;  IMMEDIATE
  749. \ force compilation of an otherwise immediate word.
  750.  
  751. :  (   [ASCII] ) parse  2DROP ;  IMMEDIATE   ( comments)
  752. : .(   [ASCII] ) parse   TYPE ;  IMMEDIATE   \ messages.
  753.  
  754. : RECURSE   last CELL+ @ , ;  IMMEDIATE   \ self-reference.
  755.  
  756. SCREEN 52
  757. ( Hall of fame--  high-level)  EXIT
  758. : M+ ( d n - d2)  { Control?}  S>D D+ ;   \ add n to d.
  759.  
  760. : >< ( u - u2)  { Control?}  DUP 255 AND  SWAP 256 * OR ;
  761. \ reverse the bytes within a cell.
  762.  
  763. : WITHIN ( u n n2 - f)  { Control?}  OVER - >R - R> U< ;
  764. \ true if n <= u < n2  given circular comparison.
  765.  
  766. : ERASE ( a u)    0 FILL ;  { CONTROLLED}
  767. : BLANK ( a u)   BL FILL ;  { CONTROLLED}
  768.  
  769. SCREEN 53
  770. ( Hall of fame--  low-level)
  771. CODE M+ ( d n - d2)           { Control?}  \ add n to d.
  772.    BX AX XCHG  CWD   BX POP  CX POP  AX CX ADD  CX PUSH
  773.    DX BX ADC   NEXT C;
  774.  
  775. CODE >< ( u - u2)  { Control?}  BL BH XCHG   NEXT C;
  776. \ reverse the bytes within a word.
  777.  
  778. : WITHIN ( u n n2 - f)  { Control?}  OVER - >R - R> U< ;
  779. \ true if n <= u < n2  given circular comparison.
  780.  
  781. : ERASE ( a u)    0 FILL ;  { CONTROLLED}
  782. : BLANK ( a u)   BL FILL ;  { CONTROLLED}
  783.  
  784. SCREEN 54
  785. \ Byte move operators
  786. : CMOVE> ( a a2 u)  { CONTROLLED}
  787. \ move u bytes from a to a2, rightmost byte first.
  788.    DUP DUP  >R  D+ R>  ?DUP
  789.    IF  0 DO  1- SWAP 1-  TUCK C@ OVER C!  LOOP THEN 2DROP ;
  790.  
  791. : MOVE ( a a2 u)   \ move u bytes from a to a2 without overlap.
  792.    >R  2DUP U< IF  R> CMOVE>  ELSE  R> CMOVE  THEN ;
  793.  
  794. : ROLL ( w[u] w[u-1]...w[0] u - w[u-1]...w[0] w[u])
  795. \ rotate kth item to top of stack.  { Delete?}
  796.    DUP  BEGIN  ?DUP WHILE  ROT >R      1- REPEAT
  797.         BEGIN  ?DUP WHILE  R> ROT ROT  1- REPEAT ;
  798.  
  799. SCREEN 55
  800. ( Double-number math-- high-level)  EXIT
  801. : S>D ( n - d)   DUP 0< ;           \ extend n to d.
  802. : D>S ( d - n)   DROP ;  { DOUBLE}  \ truncate d to n.
  803. { Require?}
  804.  
  805. : D- ( d d2 - d')   DNEGATE D+ ;  { DOUBLE}
  806.  
  807. : D2* ( d - d*2)   2DUP D+ ;
  808. : D2/ ( d - d/2)   SWAP 2/ 32767 AND         { DOUBLE}
  809.    OVER 1 AND IF  32768 OR  THEN  SWAP 2/ ;  { Require?}
  810.  
  811. SCREEN 56
  812. ( Double-number math-- low-level)
  813. CODE S>D ( n - d)   \ extend n to d.
  814.    BX AX XCHG  CWD  AX PUSH  BX DX XCHG   NEXT C;
  815. CODE D>S ( d - n)   BX POP  NEXT C;  { Req?}  \ truncate d to n.
  816.  
  817. CODE D- ( d d2 - d3)   BX DX MOV  AX POP  BX POP  CX POP
  818.    AX CX SUB  CX PUSH  DX BX SBB   NEXT C;   { DOUBLE}
  819.  
  820. CODE D2* ( d - d2)
  821.    AX POP   AX SHL  BX RCL   AX PUSH   NEXT C;
  822. CODE D2/ ( d - d2)  { DOUBLE}  { Require?}
  823.    AX POP   BX SAR  AX RCR   AX PUSH   NEXT C;
  824.  
  825. SCREEN 57
  826. \ More Double-number math
  827. : D<  ( d d2 - f)
  828.    ROT 2DUP = IF  2DROP U< EXIT THEN  2SWAP 2DROP > ;
  829.  
  830. : D0= ( d - f)         OR 0= ;    { DOUBLE}
  831. : D=  ( d d2 - f)   D- OR 0= ;    { DOUBLE}
  832.  
  833. : DABS ( d - ud)   DUP 0< IF  DNEGATE  THEN ;  { Double?}
  834.  
  835. : DMAX ( d d2 - dmax)  { DOUBLE}
  836.    2OVER 2OVER D<     IF 2SWAP THEN  2DROP ;
  837. : DMIN ( d d2 - dmin)  { DOUBLE}
  838.    2OVER 2OVER D< NOT IF 2SWAP THEN  2DROP ;
  839.  
  840. SCREEN 58 
  841. \ Double-number operators
  842. : 2CONSTANT ( - w)   CREATE  , ,  DOES> 2@ ;
  843. \ create a double constant.  { DOUBLE}
  844. : 2VARIABLE ( - a)   VARIABLE  0 THERE ! CELL ALLOT ;
  845. \ create a double variable.  { DOUBLE}
  846.  
  847. : D@ ( a - d)   2@ ;  { DOUBLE}
  848. : D! ( d a )    2! ;  { DOUBLE}
  849.  
  850. : DLITERAL ( d ) ( - d)  { Double?}  \ compile d as a literal.
  851.    SWAP [COMPILE] LITERAL [COMPILE] LITERAL ; IMMEDIATE
  852.  
  853. : D.R ( d n)  { DOUBLE}
  854. \ print d right-justified in field of width n.
  855.    >R  TUCK  DABS  <#  #S ROT SIGN  #>
  856.    R>  OVER - 0 MAX SPACES  TYPE ;
  857.  
  858. SCREEN 59
  859. ( Mixed-precision multiply and divide-- high-level)  EXIT
  860. : M* ( n n2 - d)  { Control?}
  861. \ signed mixed-precision multiply.
  862.    2DUP XOR >R  ABS SWAP ABS UM*  R> 0< IF NEGATE THEN ;
  863.  
  864. : M/MOD ( d n - rem quot)  { Control?}
  865. \ signed rounded-down mixed-precision divide.
  866.    2DUP XOR >R  OVER >R  ABS >R DABS R> UM/MOD
  867.    SWAP R> 0< IF  NEGATE  THEN
  868.    SWAP R> 0< IF  NEGATE  THEN ;
  869.  
  870. SCREEN 60
  871. ( Mixed-precision multiply and divide-- low-level)
  872. CODE M* ( n n2 - d)  { Control?}
  873. \ signed mixed-precision multiply.
  874.    BX AX XCHG  DX POP   DX IMUL   AX PUSH  DX BX MOV   NEXT C;
  875.  
  876. CODE M/MOD ( d n - rem quot)  { Control?}  DX POP  AX POP
  877. \ signed rounded-down mixed-precision divide.
  878.    BX BX OR  5 L# JZ  ( divide by zero?)
  879.    BX IDIV        AX BX MOV  DX PUSH   NEXT
  880.  5 L: AX DX MOV  0 # BX MOV  DX PUSH   NEXT C;
  881.  
  882. SCREEN 61
  883. ( Mixed-precision multiply and divide-- floored)  EXIT
  884. CODE M* ( n n2 - d)  { Control?}
  885. \ signed mixed-precision multiply.
  886.    BX AX XCHG  DX POP   DX IMUL   AX PUSH  DX BX MOV   NEXT C;
  887.  
  888. : M/MOD ( d n - rem quot)  { Control?}
  889. \ signed floored mixed-precision divide.
  890.    DUP >R  2DUP XOR >R  DUP >R  ABS >R DABS R> UM/MOD
  891.    SWAP R> 0< IF  NEGATE  THEN
  892.    SWAP R> 0< IF  NEGATE  OVER IF  R@ ROT -  SWAP 1-  THEN THEN
  893.    R> DROP ;
  894.  
  895. SCREEN 62
  896. \ Multiply and divide
  897. : /MOD ( n n2 - n3 n4)   >R DUP 0< R> M/MOD ;
  898.  
  899. : /   ( n n2 - n3)   /MOD  NIP ;
  900. : MOD ( n n2 - n3)   /MOD  DROP ;
  901.  
  902. \ Intermediate product is 32 bits:
  903. : */MOD ( n n2 n3 - n4 n5)   >R M* R> M/MOD ;
  904. : */    ( n n2 n3 - n4)      >R M* R> M/MOD  NIP ;
  905.  
  906. CODE * ( n n2 - n3)   AX POP  BX IMUL   AX BX MOV   NEXT C;
  907.  
  908. EXIT
  909. : * ( n n2 - n3)   UM* DROP ;
  910.  
  911. SCREEN 63
  912. \ Number conversion operator
  913. | : val? ( a u - d 2 , n 1 , 0)
  914. \ string to number conversion primitive.  True if d is valid.
  915. \ Returns d if number ends in final '.' and sets dpl = 0
  916. \ Returns n if no punctuation present   and sets dpl = 0<
  917.    [ #Jot 1- ] LITERAL MIN  PAD 1- OVER -  TUCK >R  CMOVE
  918.    BL PAD 1-  DUP dpl ! C!  0 0 R>
  919.    DUP C@ [ASCII] - = DUP >R - 1-
  920.    BEGIN  CONVERT  DUP C@  DUP [ASCII] : =
  921.      SWAP [ASCII] , [ASCII] / 1+ WITHIN  OR
  922.    WHILE  DUP dpl !  REPEAT  R> SWAP >R IF  DNEGATE  THEN
  923.    PAD 1- dpl @ - 1- dpl !   R> PAD 1- = ( valid?)
  924.    IF  dpl @ 0< IF DROP 1 ELSE 2 THEN  ELSE  2DROP 0  THEN ;
  925.  
  926. : VAL? ( a u - d 2 , n 1 , 0)  { Feature}  'val? @EXECUTE ;
  927.  
  928. SCREEN 64
  929. \ Interpreter proper
  930. | : val, ( ... w )
  931. \ compiles the top w stack items as numeric literals.
  932.    DUP BEGIN  ROT >R                1- ?DUP 0= UNTIL
  933.        BEGIN  R> [COMPILE] LITERAL  1- ?DUP 0= UNTIL ;
  934.  
  935. : interpret  { Feature}  \ the text compiler loop.
  936.    BEGIN  BL WORD  FIND  ?DUP
  937.      IF    STATE @ =  ( Imm?) IF  ,  ELSE EXECUTE  THEN
  938.      ELSE  COUNT VAL?  DUP huh?
  939.            STATE @ IF  val,  ELSE  DROP  THEN
  940.      THEN
  941.    AGAIN ;
  942.  
  943. SCREEN 65
  944. \ QUIT support
  945. : EVALUATE ( a u)   \ evaluate a string.
  946.    #TIB 2@ 2>R  #TIB 2!  BLK 2@ 2>R  0 0 BLK 2!  interpret
  947.    2R> BLK 2!  2R> #TIB 2! ;
  948.  
  949. : EXPECT ( a +n)   'expect @EXECUTE ;
  950.  
  951. : QUERY  { CONTROLLED}
  952. \ fill TIB from next line of input stream.
  953.    0 0 BLK 2!  TIB 80 EXPECT  SPAN @ #TIB ! ;
  954.  
  955. : ok?   \ status check.
  956.    D0 @ [ #Safe ] LITERAL -  HERE U< ABORT" No Room"
  957.    DEPTH 0< ABORT" Stack?" ;
  958.  
  959. : OK?  { Feature}  ok?  STATE @ 0= IF ." ok" THEN ;
  960.  
  961. SCREEN 66
  962. \ QUIT and ABORT
  963. : QUIT   \ default main program.
  964.    RESET  BEGIN  CR QUERY  SPACE interpret  OK?  AGAIN ;
  965.  
  966. : GRIPE ( a u)  { Feature}  \ default error handler.
  967.    BLK @ IF  BLK 2@ scr 2!  THEN
  968.    THERE COUNT TYPE SPACE  ( msg ) TYPE ;
  969.  
  970. : ABORT   BEGIN  PRESET QUIT  GRIPE  AGAIN ;
  971. \ default main program and error handler, courtesy Wil Baden.
  972.  
  973. : ABORT"   \ compile error handler and message.
  974.    [COMPILE] IF  [COMPILE] "  COMPILE err  [COMPILE] THEN ;
  975.   IMMEDIATE
  976.  
  977. SCREEN 67
  978. ( Debug-- EXIT when done)
  979. : .S  { Control?}  \ display the data stack.
  980.    DEPTH 0 MAX  ?DUP
  981.    CR  IF 0 DO  DEPTH I - 1- PICK  .  LOOP  THEN  ." <-Top " ;
  982.  
  983. : DUMP ( a u)  { RESERVED}  \ simple dump.
  984.    SPACE 0 DO  DUP 7 AND 0= IF  SPACE  THEN  DUP C@ .  1+ LOOP
  985.    DROP ;
  986.  
  987. : ? ( a)   @ . ;  { Control?}
  988.  
  989. : WORDS  { Control?}  \ simple word list.
  990.    CONTEXT @
  991.    BEGIN @ ?DUP
  992.    WHILE  DUP CELL+ COUNT 31 AND TYPE SPACE  REPEAT ;
  993.  
  994. SCREEN 68
  995. \ FORGET support
  996. | : clip ( a 'lfa)   \ unlink words below the given address.
  997.    BEGIN   DUP @
  998.    WHILE  2DUP @  SWAP U< NOT ( ie U<= )
  999.      IF    DUP @ @ OVER ! ( unlinks it )  ELSE  @  THEN
  1000.    REPEAT  2DROP ;
  1001.  
  1002. : crop ( lfa)
  1003. \ crop dictionary to the given link address.
  1004.    f CELL+ ( ie vlink)  2DUP clip
  1005.    BEGIN  @ ?DUP WHILE  2DUP CELL - @ ( ie >RAM) clip
  1006.    REPEAT  FORTH DEFINITIONS  DUP CURRENT @ clip  h ! ;
  1007.  
  1008. SCREEN 69
  1009. \ FORGET and variations
  1010. : GUARD   h H0 3 CELLS CMOVE  THERE T0 ! ;  { Feature}
  1011. : EMPTY   H0 h 3 CELLS CMOVE  T0 @  r  ! ;  { Feature}
  1012.  
  1013. : >link ( cfa - lfa)
  1014.    BEGIN  1- DUP C@ 128 AND UNTIL  CELL - ;
  1015.  
  1016. : FORGET   \ forget words from the following <name>.
  1017.    CURRENT @ CONTEXT !   ' >link
  1018.    DUP HERE H0 @ WITHIN ABORT" Can't"  crop ;
  1019. { FORGET cannot recover RAM and so is not ROMable.}
  1020. { Delete?}
  1021.  
  1022.  
  1023. SCREEN 70
  1024.  
  1025.  
  1026. SCREEN 71
  1027. \ ------ Device drivers ---------------------------
  1028. HEX
  1029. | CODE (type) ( a u)   BX CX MOV  DX POP   1 # BX MOV
  1030.    40 # AH MOV  21 INT   BX POP   'pause ) JMP C;
  1031.  
  1032. | CODE KDOS ( - key -1 , ? 0)
  1033. \ check for key pressed.
  1034. \ Special keys are returned in high byte with low byte zeroed.
  1035.    BX PUSH   FF # DL MOV   6 # AH MOV   21 INT
  1036.    0 # BX MOV  2 L# JE      AH AH SUB   ( special key?)
  1037.    AL AL OR    1 L# JNZ    7 # AH MOV   21 INT
  1038.    AH AH SUB   AL AH XCHG
  1039.  1 L: TRUE # BX MOV   2 L: AX PUSH   'pause ) JMP C;
  1040.  
  1041. SCREEN 72
  1042. \ KEY and EMIT actions
  1043.   13 EQU #EOL ( end-of-line)   10 EQU #LF  ( line-feed)
  1044. HERE EQU $Eol  #EOL C, #LF C,   2 EQU #Eol
  1045.  
  1046. | : (cr)   $Eol #Eol (type) ;
  1047.  
  1048. | : (key?) ( - f)   \ true if key pressed since last KEY.
  1049.    key' @ 0= IF  KDOS  key' 2!  THEN  key' @ ;
  1050.  
  1051. : KEY ( - n)   BEGIN  (key?) UNTIL  key' CELL+ @  0 key' ! ;
  1052. : EMIT ( b)   hld C!  hld 1 TYPE ;
  1053.  
  1054. SCREEN 73
  1055. \ EXPECT action
  1056. 08   EQU #BSP ( backspace)    127 EQU #DEL ( delete)
  1057. 27   EQU #ESC ( escape)
  1058. HERE EQU $Bsp ( * ) 3 C, #BSP C, BL C, #BSP C,
  1059.  
  1060. | : expect ( a +n)   >R  0  ( a o)
  1061. \ read upto +n chars into address; stop at #EOL or #ESC
  1062.    BEGIN  DUP R@ <
  1063.    WHILE  KEY 127 ( 7-bit ASCII) AND
  1064.      DUP #BSP =  OVER #DEL = OR
  1065.      IF    DROP  DUP IF  1-  $Bsp COUNT TYPE  THEN
  1066.      ELSE  DUP #EOL = OVER #ESC = OR
  1067.        IF  DROP  SPAN !  R> 2DROP  EXIT  THEN
  1068.        ( otherwise) BL MAX >R  2DUP +  R> OVER C!  1 TYPE  1+
  1069.      THEN
  1070.    REPEAT  SPAN !  R> 2DROP ;
  1071.  
  1072. SCREEN 74
  1073. \ Dumb terminal actions
  1074. | : (keys) ( a +n)   >R  0  ( a o)
  1075. \ read upto +n chars into address without echo; stop at #EOL
  1076.    BEGIN  DUP R@ <
  1077.    WHILE  KEY  DUP #EOL =
  1078.      IF  R> 2DROP  DUP >R  ( early out)
  1079.      ELSE  BL MAX >R  2DUP +  R> SWAP C!  1+  THEN
  1080.    REPEAT  SPAN !  R> 2DROP ;
  1081.  
  1082. | : (mark) ( a n)    ." ^"  TYPE ;
  1083. | : (page)   25 0 DO  CR  LOOP ;
  1084. | : (tab)  ( n n2)    CR  DROP SPACES ;
  1085.  
  1086. SCREEN 75
  1087. \ Initialize automatic variables
  1088. HERE EQU RAMs
  1089. ] nope expect source nope nope  val? [
  1090. ( key' ) 0 , 0 ,
  1091. HERE RAMs - EQU #RAMs
  1092.  
  1093.  
  1094. SCREEN 76
  1095.  
  1096.  
  1097. SCREEN 77
  1098. \ ------ Initialization ---------------------------
  1099. D0 CONSTANT parms   \ System parameter table.
  1100.  
  1101. CREATE glass        \ Simple transfer table.
  1102. ] (type) (cr)  (keys) (key?)  (mark) (page)  (tab) nope [
  1103.  
  1104. : READY  ." Ready" ;  { Feature}  \ Initialize application.
  1105. : BYE    0 EXECUTE ;  { Feature}  \ Shut down  application.
  1106.  
  1107.  
  1108. SCREEN 78
  1109. \ Initialization-- high-level
  1110. 160 CONSTANT VERSION  { Feature}  \ ZEN 1.60
  1111.  
  1112. | : vocabs   \ initialize vocabularies.
  1113.    f CELL+ ( ie vlink)
  1114.    BEGIN  @ ?DUP
  1115.    WHILE  DUP CELL+ @ OVER CELL - @ ( ie >RAM) !  REPEAT ;
  1116.  
  1117. | : cold   \ high-level coldstart initialization.
  1118.    TRUE ( wake) entry entry 2!  T0 2@ r 2!   glass x !
  1119.    RAMs 'pause #RAMs CMOVE
  1120.    EMPTY  vocabs  PRESET  FORTH DEFINITIONS  DECIMAL
  1121.    " READY" EVALUATE   ABORT ;
  1122.  
  1123. \ If all definitions are headerless, substitute:  READY  ABORT ;
  1124.  
  1125. SCREEN 79
  1126. \ Initialization-- low-level
  1127. HEX  HERE ( *) ," No Room $"
  1128.  
  1129. | CODE Coldstart   \ low-level initialization.
  1130.    1000 # BX MOV   4A # AH MOV   21 INT  ( enough room?)
  1131.  1 L# JNC  ( No:)
  1132.    ( *) 1+ # DX MOV   9 # AH MOV   21 INT   0 # JMP  ( Bye)
  1133.  1 L: #SP0 # SP MOV   #RP0 # BP MOV   BP u ) MOV
  1134.    ' cold >BODY # SI MOV  ( I register)   NEXT C;
  1135.  
  1136. HERE ( * ) Power ORG   ASSEMBLER  ' Coldstart # JMP C;
  1137.      ( * )       ORG
  1138.  
  1139.  
  1140. SCREEN 80
  1141.  
  1142. SCREEN 81
  1143. \ ------ FILE extension ---------------------------
  1144. #Used USER IO-RESULT  DROP
  1145.  
  1146. 26  EQU #EOF  \ control-Z marks the end of older text files.
  1147.  
  1148. 128 EQU buff  \ MS-DOS command tail and default fcb buffer.
  1149. 192 EQU name  \ RENAME-FILE takes two names.
  1150.  
  1151. 256  buff - EQU #buff   \ size of buffer in bytes.
  1152. name buff - EQU #name   \ size of name in bytes plus zero.
  1153.  
  1154. | : >fname ( a u - a2)   \ convert string to ASCIIZ file name.
  1155.    buff  2DUP 2>R  SWAP MOVE  R@  0 2R> + C! ;
  1156.  
  1157. SCREEN 82
  1158. \ MS-DOS interface
  1159. HEX
  1160. CODE fdos ( DX CX handle function# - AX)
  1161. \ generic call to MS-DOS
  1162.    BX AX MOV  BX POP  CX POP  DX POP   21 INT
  1163. LABEL return   AX BX MOV   1 L# JB   AX AX SUB   2 L# JZ
  1164.  1 L: BX BX SUB ( non-zero retcode forces zero result)
  1165.  2 L: u ) DI MOV   AX IO-RESULT entry - [DI] MOV   NEXT C;
  1166.  
  1167. | CODE rename ( a a2 function# - AX)
  1168.    BX AX MOV  DI POP  DX POP   21 INT   return JU C;
  1169.  
  1170. | CODE seek ( DX CX handle function# - AX DX)
  1171.    BX AX MOV  BX POP  CX POP  DX POP   21 INT
  1172.    DX PUSH   return JU C;
  1173.  
  1174. SCREEN 83
  1175. \ 5 file primitives
  1176. HEX
  1177. : OPEN-FILE   ( a u - w)   >fname  0 0 3D02 fdos ;
  1178. : CREATE-FILE ( a u - w)   >fname  0 0 3C00 fdos ;
  1179.  
  1180. : DELETE-FILE ( a u)   >fname  0 0 4100 fdos  DROP ;
  1181. : CLOSE-FILE  ( w)     0 0 ROT     3E00 fdos  DROP ;
  1182.  
  1183. : RENAME-FILE ( a u a2 u2)
  1184.    >fname  name #name CMOVE>
  1185.    >fname  name  5600 rename  DROP ;
  1186.  
  1187. SCREEN 84
  1188. \ Read, write and seek bytes
  1189. HEX
  1190. \ Read or write u bytes to or from address a to file w.
  1191. : READ-FILE  ( a u w - u2)   3F00 fdos ;
  1192. : WRITE-FILE ( a u w - u2)   4000 fdos ;
  1193.  
  1194. : SEEK-FILE ( doff n w - dpos)   \ add an offset to file w.
  1195. \ n neg: to start; n pos: to end; n zero: to current.
  1196.    SWAP DUP IF  0< CELLS 1+  THEN  4201 + seek ;
  1197.  
  1198. \ Return file position or size.
  1199. : FILEPOS  ( w - d)   >R  0 0 0 R> SEEK-FILE ;
  1200. : FILESIZE ( w - d)   >R  0 0 1 R> SEEK-FILE ;
  1201.  
  1202. SCREEN 85
  1203. \ Read and write lines of text
  1204. : WRITE-CR ( w)   $Eol #Eol ROT WRITE-FILE  DROP ;
  1205.  
  1206. : READ-LINE ( a u w - 0 0 | u2 t)
  1207. { Greater performance will result if the end-of-line sequence  }
  1208. { is read into the address and the size u adjusted accordingly.}
  1209.    >R  buff OVER 1+ #buff MIN R@ READ-FILE  ( a u u2)
  1210.    DUP 0= IF  R> 2DROP 2DROP  0 0 EXIT THEN ( end of file)
  1211.    buff OVER #EOL SCAN  NIP ( a u u2 u3)
  1212.    ?DUP IF   #Eol OVER - >R -
  1213.         ELSE  2DUP U< >R  THEN  MIN R> ( a u4 #seek)
  1214.    ?DUP IF  S>D 0 R@ SEEK-FILE 2DROP  THEN
  1215.    buff OVER #EOF SCAN  NIP -   ( remove if no control-Zs)
  1216.    R> DROP ( a u4) >R  buff SWAP R@ CMOVE>  R> TRUE ;
  1217.  
  1218. SCREEN 86
  1219. \ Load and save files
  1220. : GO ( a u)  { Feature}  \ evaluate the KERNEL.SRC file.
  1221.    " KERNEL.SRC" OPEN-FILE DUP huh?  ( w) >R
  1222.    BEGIN  buff  DUP 64 R@ READ-LINE
  1223.    WHILE  EVALUATE  REPEAT  2DROP   R> CLOSE-FILE ;
  1224.  
  1225. : SAVE-FILE ( a u)  { Feature}  \ save the dictionary by name.
  1226.    CREATE-FILE DUP huh?  ( w) >R
  1227.    'pause RAMs #RAMs CMOVE   GUARD   f CELL+ ( ie vlink)
  1228.    BEGIN  @ ?DUP ( save vocabularies)
  1229.    WHILE  DUP CELL - @ ( ie >RAM) @ OVER CELL+ !  REPEAT
  1230.    256  HERE OVER - R@ WRITE-FILE  DROP   R> CLOSE-FILE ;
  1231.  
  1232. SCREEN 87
  1233. \ BLOCK word set
  1234. VARIABLE system    VARIABLE block#    VARIABLE update
  1235. VARIABLE buffer  1024 CELL - ALLOT
  1236.  
  1237. : seek-block ( u w - a n w)
  1238.    >R  1024 UM* TRUE  R@ SEEK-FILE 2DROP  buffer 1024 R> ;
  1239.  
  1240. : SAVE-BUFFERS  { BLOCK}  system @ 0= ABORT" No File"
  1241.    system 2@ seek-block WRITE-FILE DROP ;
  1242.  
  1243. : BUFFER ( u - a)  { BLOCK}  >R  block# 2@  R@ - AND
  1244.    IF  SAVE-BUFFERS  THEN   0 R> block# 2!  buffer ;
  1245.  
  1246. : BLOCK  ( u - a)  { BLOCK}
  1247.    DUP block# @ = IF  DROP buffer  EXIT THEN
  1248.    BUFFER >R  system 2@ seek-block READ-FILE DROP  R> ;
  1249.  
  1250. SCREEN 88
  1251. \ BLOCK support
  1252. : EMPTY-BUFFERS  { CONTROLLED}  0 TRUE block# 2! ;
  1253.  
  1254. HEX
  1255. : UPDATE  { BLOCK}  TRUE update ! ;
  1256. : FLUSH   { BLOCK}
  1257.    SAVE-BUFFERS  0 0 system @ 4500 fdos  CLOSE-FILE ;
  1258.  
  1259. : LOAD ( u)  { BLOCK}
  1260.    BLK 2@ 2>R  0 SWAP BLK 2!  interpret  2R> BLK 2! ;
  1261.  
  1262. : block   BLK @ ?DUP IF  BLOCK 1024  ELSE  #TIB 2@  THEN ;
  1263.  
  1264. \ Use this definition if the BLOCK word set is compiled:
  1265. : READY   ." Ready!"    ['] block 'source !
  1266.    " NEW.SCR" OPEN-FILE  DUP huh?  system !  EMPTY-BUFFERS ;
  1267.  
  1268.  
  1269.